#include "CogObjective.h"
#include "CogRegister.h"

// ------------------------------------------------------------------------------------------

CogEvaluator* CogObjective::create(const string& _name, const string& _parameter, size_t _rank) 
{ 
	if (pEvaluator = CogRegister::create(_name, _parameter))
	{
		name = _name;
		parameter = _parameter;
		rank = _rank;
	}
	return pEvaluator; 
}

// ------------------------------------------------------------------------------------------

void CogMultiObjective::addObjective(const CogObjective& objective)
{
	if (objective.rank >= table.size())
	{
		table.resize(objective.rank+1);
	}
	table[objective.rank].push_back(objective);
}

void CogMultiObjective::clear()
{
	for (size_t i = 0; i < table.size(); i++)
	{
		for (size_t j = 0; j < table[i].size(); j++)
		{
			table[i][j].destroy();
		}
	}
	table.clear();
}

void CogMultiObjective::evaluate(CogSolution& solution)
{
	for (size_t i = 0; i < table.size(); i++)
	{
		for (size_t j = 0; j < table[i].size(); j++)
		{
			solution.result[i][j] = table[i][j].pEvaluator->evaluate(solution.pRule);
		}
	}
}

bool CogMultiObjective::dominates(CogSolution& first, CogSolution& second, size_t stage)
{
	size_t dominating = 0;
	for (size_t i = 0; i < table[stage].size(); i++)
	{
		if (second.result[stage][i] < first.result[stage][i])
		{
			return false;
		}
		else
		if (second.result[stage][i] > first.result[stage][i])
		{
			dominating++;
		}
	}
	return (dominating > 0);
}

void CogMultiObjective::toStream(ostream &out)
{
	for (size_t i = 1; i < table.size(); i++) // start at 1 (0 is non-objective)
	{
		for (size_t j = 0; j < table[i].size(); j++)
		{
			string label;
			switch (table[i][j].pEvaluator->getCacheMode())
			{
				case COGCM_VALUE:
					label = "objective&value";
					break;
				case COGCM_STACK:
					label = "objective&stack";
					break;
				case COGCM_OFF:
					label = "objective";
					break;
			}
			out << "@ " << label.c_str() << "<" << i+1 << ">" << " = " << table[i][j].name << "<" << table[i][j].parameter << ">" << endl;
		}
	}
	for (size_t j = 0; j < table[0].size(); j++) // non-objective measures
	{
		string label;
		switch (table[0][j].pEvaluator->getCacheMode())
		{
			case COGCM_VALUE:
				label = "measure&value";
				break;
			case COGCM_STACK:
				label = "measure&stack";
				break;
			case COGCM_OFF:
				label = "measure";
				break;
		}
		out << "@ " << label.c_str() << " = " << table[0][j].name << "<" << table[0][j].parameter << ">" << endl;
	}
}

// ------------------------------------------------------------------------------------------

bool CogSolution::hasPrimaryZero()
{
	for (size_t i = 0; i < result.size(); i++)
	{
		if (result[i].size())
		{
			for (size_t j = 0; j < result[i].size(); j++)
			{
				if (result[0][j])
				{
					return false;
				}
			}
			break;
		}
	}
	return true;
}

// ------------------------------------------------------------------------------------------

// assumes both results have the same number and order of objectives
bool cogSolutionCompare(const CogSolution& left, const CogSolution& right) 
{
	for (size_t i = 1; i < left.result.size(); i++) // start at 1 (0 is non-objective)
	{
		if (left.result[i].size() == 1)
		{
			if (left.result[i][0] != right.result[i][0])
			{
				return left.result[i][0] < right.result[i][0];
			}
		}
		else
		if (left.result[i].size() > 1)
		{
			if (left.result[i].rank != right.result[i].rank)
			{
				return left.result[i].rank < right.result[i].rank;
			}
		}
	}
	return false;
}

bool(*fpSolutionCompare)(const CogSolution&, const CogSolution&) = cogSolutionCompare;

// ------------------------------------------------------------------------------------------
